<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>煤层气朗缪尔等温吸附曲线绘制工具</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
    <style>
        /* 学术风格 - 经典黑白灰配色 */
        :root {
            --primary-text: #000000;
            --secondary-text: #333333;
            --background-color: #f9f9f9;
            --paper-color: #ffffff;
            --border-color: #cccccc;
            --grid-color: #e0e0e0;
            --accent-color: #555555;
            --highlight-color: #000000;
            --card-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
            --spacing-xs: 5px;
            --spacing-sm: 10px;
            --spacing-md: 15px;
            --spacing-lg: 20px;
            --spacing-xl: 30px;
        }
        
        body {
            font-family: 'Times New Roman', 'Computer Modern', serif;
            background-color: var(--background-color);
            color: var(--primary-text);
            line-height: 1.6;
            margin: 0;
            padding: 0;
        }
        
        .container {
            max-width: 1200px;
            margin: var(--spacing-xl) auto;
            padding: 0 var(--spacing-lg);
        }
        
        .paper {
            background-color: var(--paper-color);
            padding: var(--spacing-xl);
            border-radius: 4px;
            box-shadow: var(--card-shadow);
        }
        
        h1 {
            color: var(--primary-text);
            text-align: center;
            font-size: 32px;
            font-weight: bold;
            margin-bottom: var(--spacing-sm);
            padding-bottom: 0;
        }

        h2 {
            color: var(--primary-text);
            font-size: 24px;
            font-weight: bold;
            margin-top: var(--spacing-sm);
            margin-bottom: var(--spacing-lg);
            padding-bottom: 0;
        }
        
        h3 {
            color: var(--secondary-text);
            font-size: 20px;
            font-weight: bold;
            margin-top: var(--spacing-lg);
            margin-bottom: var(--spacing-md);
        }
        
        .card {
            background-color: var(--paper-color);
            border: 1px solid var(--border-color);
            border-radius: 4px;
            padding: var(--spacing-lg);
            margin-bottom: var(--spacing-xl);
            box-shadow: var(--card-shadow);
        }
        
        .form-group {
            margin-bottom: var(--spacing-lg);
        }
        
        .form-row {
            display: flex;
            flex-wrap: wrap;
            gap: var(--spacing-lg);
            margin-bottom: var(--spacing-lg);
        }
        
        .form-item {
            flex: 1;
            min-width: 180px;
            margin-right: var(--spacing-md);
            max-width: 280px;
        }
        
        .form-item:last-child {
            margin-right: 0;
        }
        
        input[type="number"],
        input[type="text"] {
            width: 180px; /* 设置统一的固定宽度 */
            padding: var(--spacing-sm);
            border: 1px solid var(--border-color);
            border-radius: 4px;
            font-size: 16px;
            background-color: var(--paper-color);
            transition: border-color 0.3s;
            margin: 0 auto; /* 居中显示 */
            display: block;
        }
        
        /* 响应式设计优化 */
        @media (max-width: 768px) {
            .form-row {
                flex-direction: column;
            }
            
            .form-item {
                margin-right: 0;
                max-width: 100%;
            }
            
            input[type="number"],
            input[type="text"] {
                max-width: 100%;
            }
            
            .input-group {
                flex-direction: column;
                align-items: flex-start;
            }
            
            .input-group input {
                width: 100%;
            }
            
            .chart-container {
                aspect-ratio: 16/9;
                height: auto;
            }
        }
        
        label {
            display: block;
            margin-bottom: var(--spacing-sm);
            font-weight: bold;
            color: var(--secondary-text);
            font-size: 16px;
        }
        
        input[type="number"]:focus,
        input[type="text"]:focus {
            border-color: var(--accent-color);
            outline: none;
        }
        
        button {
            background-color: var(--accent-color);
            color: white;
            border: none;
            padding: var(--spacing-sm) var(--spacing-lg);
            text-align: center;
            text-decoration: none;
            display: inline-block;
            font-size: 16px;
            margin: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) 0;
            cursor: pointer;
            border-radius: 4px;
            transition: background-color 0.3s;
        }
        
        button:hover {
            background-color: var(--primary-text);
        }
        
        .chart-container {
            position: relative;
            aspect-ratio: 16/9;
            height: auto;
            max-height: 500px;
            margin: 0 auto var(--spacing-xl) auto;
            border: 1px solid var(--border-color);
            background-color: var(--paper-color);
            padding: var(--spacing-md);
            display: block;
        }
        
        .modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            z-index: 1000;
            align-items: center;
            justify-content: center;
        }
        
        .modal-content {
            background-color: var(--paper-color);
            padding: var(--spacing-xl);
            border-radius: 4px;
            box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
            max-width: 500px;
            width: 90%;
            max-height: 90vh;
            overflow-y: auto;
        }
        
        .modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: var(--spacing-lg);
            padding-bottom: var(--spacing-md);
            border-bottom: 1px solid var(--border-color);
        }
        
        .modal-title {
            margin: 0;
            font-size: 24px;
            color: var(--primary-text);
        }
        
        .modal-close {
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            color: var(--secondary-text);
            padding: 0;
            margin: 0;
        }
        
        .modal-close:hover {
            color: var(--primary-text);
        }
        
        .modal-body {
            margin-bottom: var(--spacing-lg);
        }
        
        .modal-footer {
            display: flex;
            justify-content: flex-end;
            gap: var(--spacing-md);
        }
        
        .export-option {
            display: flex;
            align-items: center;
            padding: var(--spacing-md);
            margin-bottom: var(--spacing-md);
            background-color: #f5f5f5;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s;
        }
        
        .export-option:hover {
            background-color: #e9e9e9;
        }
        
        .export-icon {
            margin-right: var(--spacing-md);
            font-size: 24px;
            color: var(--accent-color);
        }
        
                .result-container {
            margin-top: 20px;
            padding: var(--spacing-md);
            border-left: 4px solid var(--accent-color);
            background-color: #f8f9fa;
            color: var(--secondary-text);
            border-radius: 0 4px 4px 0;
        }

        .result-container.success {
            background-color: #f0f9f0;
            border-left-color: #28a745;
            color: #28a745;
        }
        
        .result-container.error {
            background-color: #fdf2f2;
            border-left-color: #dc3545;
            color: #dc3545;
        }
        
        /* 表格样式 */
        .result-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: var(--spacing-md);
            font-family: 'Times New Roman', serif;
        }
        
        .result-table th {
            background-color: #f2f2f2;
            border: 1px solid var(--border-color);
            padding: var(--spacing-sm);
            text-align: left;
            font-weight: bold;
        }
        
        .result-table td {
            border: 1px solid var(--border-color);
            padding: calc(var(--spacing-sm) - 2px) var(--spacing-sm);
        }
        
        .result-table tr:nth-child(even) {
            background-color: #f9f9f9;
        }
        
        /* 按钮样式 */
        .delete-btn {
            background-color: #dc3545;
            color: white;
            border: none;
            padding: 5px 10px;
            cursor: pointer;
            border-radius: 4px;
            font-size: 12px;
        }
        
        .delete-btn:hover {
            background-color: #c82333;
        }
        
        /* 隐藏/显示按钮样式 */
        .toggle-btn {
            background-color: #007bff;
            color: white;
            border: none;
            padding: 5px 10px;
            cursor: pointer;
            border-radius: 4px;
            font-size: 12px;
            margin-right: 5px;
        }
        
        .toggle-btn:hover {
            background-color: #0056b3;
        }
        
        .clear-btn {
            background-color: #ffc107;
            color: #212529;
            border: none;
            padding: 8px 15px;
            cursor: pointer;
            border-radius: 4px;
            margin-top: var(--spacing-md);
            font-size: 14px;
        }
        
        .copy-btn {
            background-color: #28a745;
            color: white;
            border: none;
            padding: 8px 15px;
            cursor: pointer;
            border-radius: 4px;
            margin-top: var(--spacing-md);
            margin-left: 10px;
            font-size: 14px;
        }
        
        .copy-btn:hover {
            background-color: #218838;
        }
        
        .clear-btn:hover {
            background-color: #e0a800;
        }
        
        /* 公式容器样式，包含收缩功能 */
        .formula-container {
            background-color: #f8f8f8;
            padding: var(--spacing-lg);
            border-radius: 4px;
            margin-bottom: var(--spacing-lg);
            border: 1px solid var(--border-color);
            font-family: 'Times New Roman', serif;
            transition: all 0.3s ease;
            overflow: hidden;
        }
        
        .formula-container.collapsed {
            max-height: 0;
            padding: 0 var(--spacing-lg);
            margin-bottom: 0;
            border-top: none;
        }
        
        .formula-title {
            font-weight: bold;
            margin-bottom: var(--spacing-sm);
            color: var(--primary-text);
        }
        
        .formula {
            margin-bottom: var(--spacing-md);
            padding: var(--spacing-sm);
            background-color: var(--paper-color);
            border-radius: 4px;
            border: 1px solid var(--border-color);
        }
        
        /* 收缩功能其他样式 */
        .collapsible-title {
            display: flex;
            justify-content: space-between;
            align-items: center;
            cursor: pointer;
            padding: var(--spacing-md) 0;
            user-select: none;
        }
        
        .collapsible-title h2 {
            margin: 0;
        }
        
        .toggle-icon {
            font-size: 18px;
            transition: transform 0.3s ease;
            display: inline-block;
        }
        
        .toggle-icon.open {
            transform: rotate(45deg);
        }
        
        .chart-content {
            transition: all 0.3s ease;
            overflow: hidden;
        }
        
        .chart-content.collapsed {
            max-height: 0;
            margin-bottom: 0;
        }
        
        .input-group {
            display: flex;
            flex-wrap: wrap;
            align-items: flex-start;
            margin-bottom: var(--spacing-md);
            gap: 5px;
        }
        
        .input-group label {
            margin-bottom: 0;
            min-width: 100px;
        }
        
        .input-group input {
            width: 150px;
            flex-shrink: 0;
        }
        
        /* 响应式设计 */
        @media (max-width: 768px) {
            .form-row {
                flex-direction: column;
            }
            
            .input-group {
                flex-direction: column;
                align-items: flex-start;
            }
            
            .input-group input {
                width: 100%;
            }
            
            .chart-container {
                height: 300px;
            }
        }
        
        /* 分隔线 */
        hr {
            border: 0;
            height: 1px;
            background-color: var(--border-color);
            margin: var(--spacing-lg) 0;
        }
        
        /* 参数说明区 */
        .param-section {
            background-color: #f8f8f8;
            padding: var(--spacing-lg);
            border-radius: 4px;
            margin: var(--spacing-lg) 0;
            border: 1px solid var(--border-color);
        }
        
        .param-section p {
            margin: var(--spacing-sm) 0;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="paper">
            <h1 style="font-size: 30px;">煤层气朗缪尔等温吸附曲线绘制工具</h1>
            <h2 style="text-align: center; font-family: 'Times New Roman', serif; font-weight: normal; margin-top: 0;">Coalbed Methane Langmuir Isotherm Adsorption Curve Drawing Tool</h2>
            <p style="text-align: center; font-size: 14px; margin-top: 10px; color: var(--secondary-text);">Version: 2.0 | Author: yangjie.li | Company: AAGI</p>
            
            <!-- 基础参数输入 -->
            <div class="card">
                <h2>基础参数输入</h2>
                <div class="form-row">
                    <div class="form-item">
                        <label for="blockName">区块名称</label>
                        <input type="text" id="blockName" placeholder="输入区块名称">
                    </div>
                    <div class="form-item">
                        <label for="coalSeam">煤层号</label>
                        <input type="text" id="coalSeam" placeholder="输入煤层号">
                    </div>
                    <div class="form-item">
                        <label for="gasContent" id="gasContentLabel" style="cursor: pointer; user-select: none;" oncontextmenu="toggleCriticalPressure(event)">含气量 (m³/t)</label>
                        <input type="text" id="gasContent" placeholder="输入含气量">
                        <input type="text" id="criticalPressure" placeholder="输入临界解吸压力 (MPa)" style="display: none;">
                    </div>
                    <div class="form-item">
                        <label for="langmuirVolume">兰氏体积 (V<sub>L</sub>, m³/t)</label>
                        <input type="number" id="langmuirVolume" placeholder="输入兰氏体积" step="0.01" min="0">
                    </div>
                    <div class="form-item">
                        <label for="langmuirPressure">兰氏压力 (P<sub>L</sub>, MPa)</label>
                        <input type="number" id="langmuirPressure" placeholder="输入兰氏压力" step="0.01" min="0">
                    </div>
                </div>
                
                <!-- 压力范围和间隔设置 -->
                <div class="form-row">
                    <div class="form-item" style="text-align: left;">
                        <label for="minPressure" style="text-align: left; display: block;">最小压力 (MPa)</label>
                        <input type="number" id="minPressure" placeholder="输入最小压力" step="0.1" min="0" value="0" style="margin: 0;">
                    </div>
                    <div class="form-item" style="text-align: left;">
                        <label for="maxPressure" style="text-align: left; display: block;">最大压力 (MPa)</label>
                        <input type="number" id="maxPressure" placeholder="输入最大压力" step="0.1" min="0" value="20" style="margin: 0;">
                    </div>
                    <div class="form-item" style="text-align: left;">
                        <label for="pressureInterval" style="text-align: left; display: block;">压力间隔 (MPa)</label>
                        <input type="number" id="pressureInterval" placeholder="输入压力间隔" step="0.1" min="0.1" value="0.5" style="margin: 0;">
                    </div>
                    <div class="form-item" style="text-align: left;">
                        <label for="pointCount" style="text-align: left; display: block;">数据点数量</label>
                        <input type="number" id="pointCount" placeholder="输入数据点数量" step="1" min="10" max="1000" value="50" style="margin: 0;">
                    </div>
                </div>
                
                <button id="generateBtn">生成曲线</button>
            <button id="addKeyPointsBtn">添加关键压力点</button>
            <button id="saveDataBtn">保存数据</button>
                <button id="loadDataBtn">加载数据</button>
                <button id="exportDataBtn">导出数据</button>
                <button id="saveImageBtn">保存图像</button>
                <div id="progressBarContainer" style="display: none; width: 100%; height: 20px; background-color: #f1f1f1; border-radius: 5px; margin: 10px 0;">
                    <div id="progressBar" style="height: 100%; width: 0%; background-color: #4CAF50; border-radius: 5px; transition: width 0.3s ease;"></div>
                </div>
                <div id="operationResult" class="result-container"></div>
            </div>
            
            <!-- 公式说明 -->
            <div class="card">
                <div class="collapsible-title" onclick="toggleFormulaSection()">
                    <h2>公式说明</h2>
                    <span id="formulaToggleIcon" class="toggle-icon">+</span>
                </div>
                <div id="formulaContent" class="formula-container collapsed">
                    <div class="formula-title">朗缪尔等温吸附公式：</div>
                    <div class="formula">V = V<sub>L</sub> × P / (P<sub>L</sub> + P)</div>
                    
                    <div class="formula-title">一阶导数公式：</div>
                    <div class="formula">dV/dP = V<sub>L</sub> × P<sub>L</sub> / (P<sub>L</sub> + P)²</div>
                    
                    <div class="formula-title">二阶导数公式：</div>
                    <div class="formula">d²V/dP² = -2 × V<sub>L</sub> × P<sub>L</sub> / (P<sub>L</sub> + P)³</div>
                    
                    <div class="formula-title">曲率公式：</div>
                    <div class="formula">K = |d²V/dP²| / (1 + (dV/dP)²)^(3/2)</div>
                    
                    <div class="formula-title">曲率导数公式：</div>
                    <div class="formula">dK/dP = |d³V/dP³ × (1 + (dV/dP)²)^(3/2) - |d²V/dP²| × 3/2 × (1 + (dV/dP)²)^(1/2) × 2 × dV/dP × d²V/dP²| / (1 + (dV/dP)²)^3</div>
                    
                    <div class="formula-title">启动压力定义：</div>
                    <div class="formula">曲率导数首次达到最大值 (dK/dP = max)；吸附开始显著加速的压力点</div>
                    
                    <div class="formula-title">转折压力定义：</div>
                    <div class="formula">曲率导数通过零点 (dK/dP = 0)；曲率达到最大值的压力点，吸附速率从增加转为减小</div>
                    
                    <div class="formula-title">敏感压力定义：</div>
                    <div class="formula">曲率导数达到最小值 (dK/dP = min)；吸附速率变化最剧烈的压力点</div>
                    
                    <div class="formula-title">校正压力计算公式：</div>
                    <div class="formula">校正压力 = 原始压力 × 饱满系数<br>
                    饱满系数 = 临界解吸压力对应的含气量 / 兰氏体积</div>
                    
                    <div class="formula-title">校正压力说明：</div>
                    <div class="formula">基于临界解吸压力对应的含气量与兰氏体积的比值，对关键压力点进行校正，以反映实际吸附状态。显示格式：原始值(校正值) MPa</div>
                    
                    <div class="formula-title">公式参数说明：</div>
                    <div class="formula">V：吸附气量 (m³/t)<br>
                    P：压力 (MPa)<br>
                    V<sub>L</sub>：兰氏体积 (m³/t)<br>
                    P<sub>L</sub>：兰氏压力 (MPa)</div>
                </div>
            </div>
            
            <!-- 数据计算功能 -->
            <div class="card">
                <div class="collapsible-title" onclick="toggleCalculationSection()">
                    <h2>数据计算</h2>
                    <span id="calculationToggleIcon" class="toggle-icon">+</span>
                </div>
                <div id="calculationContent" class="formula-container">
                    <div style="margin-bottom: 10px; display: block;">
                        <label style="display: inline-block; margin-right: 5px;">输入压力 (MPa)：</label>
                        <input type="number" id="inputPressure" step="0.01" min="0" placeholder="输入压力" style="width: 140px; margin-right: 5px; display: inline-block; vertical-align: middle;">
                        <button id="calcByPressure" style="display: inline-block; vertical-align: middle;">计算吸附量</button>
                    </div>
                    <div style="margin-bottom: 10px; display: block;">
                        <label style="display: inline-block; margin-right: 5px;">输入吸附量 (m³/t)：</label>
                        <input type="number" id="inputVolume" step="0.01" min="0" placeholder="输入吸附量" style="width: 140px; margin-right: 5px; display: inline-block; vertical-align: middle;">
                        <button id="calcByVolume" style="display: inline-block; vertical-align: middle;">计算压力</button>
                    </div>
                    <button id="clearCalculationBtn" class="clear-btn">清除计算结果</button>
                    <button id="copyTableBtn" class="copy-btn">复制表格数据</button>
                    <div id="calculationResult" class="result-container">
                        <table id="resultTable" class="result-table">
                            <thead>
                                <tr>
                                    <th style="text-align: center;">名称</th>
                                    <th style="text-align: center;">压力 (MPa)</th>
                                    <th style="text-align: center;">吸附量 (m³/t)</th>
                                    <th style="text-align: center;">曲率值</th>
                                    <th style="text-align: center;">曲率导数值</th>
                                    <th style="text-align: center;">操作</th>
                                </tr>
                            </thead>
                            <tbody id="resultTableBody"></tbody>
                        </table>
                    </div>
                </div>
            </div>
            
            <!-- 图表区域 -->
            <div class="card">
                <div class="collapsible-title" onclick="toggleChartSection('adsorptionChartContainer')">
                    <h2>等温吸附曲线图版</h2>
                    <span class="toggle-icon open">+</span>
                </div>
                <div id="adsorptionChartContainer" class="chart-content">
                    <div class="chart-container">
                        <canvas id="adsorptionChart"></canvas>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <div class="collapsible-title" onclick="toggleChartSection('curvatureChartContainer')">
                    <h2>等温吸附曲率图版</h2>
                    <span class="toggle-icon open">+</span>
                </div>
                <div id="curvatureChartContainer" class="chart-content">
                    <div class="chart-container">
                        <canvas id="curvatureChart"></canvas>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <div class="collapsible-title" onclick="toggleChartSection('firstDerivativeChartContainer')">
                    <h2>等温吸附一阶导数曲线图版</h2>
                    <span class="toggle-icon">+</span>
                </div>
                <div id="firstDerivativeChartContainer" class="chart-content collapsed">
                    <div class="chart-container">
                        <canvas id="firstDerivativeChart"></canvas>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <div class="collapsible-title" onclick="toggleChartSection('secondDerivativeChartContainer')">
                    <h2>等温吸附二阶导数曲线图版</h2>
                    <span class="toggle-icon">+</span>
                </div>
                <div id="secondDerivativeChartContainer" class="chart-content collapsed">
                    <div class="chart-container">
                        <canvas id="secondDerivativeChart"></canvas>
                    </div>
                </div>
            </div>
            
            <div class="card">
                <div class="collapsible-title" onclick="toggleChartSection('curvatureDerivativeChartContainer')">
                    <h2>等温吸附曲率导数图版</h2>
                    <span class="toggle-icon">+</span>
                </div>
                <div id="curvatureDerivativeChartContainer" class="chart-content collapsed">
                    <div class="chart-container">
                        <canvas id="curvatureDerivativeChart"></canvas>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 全局变量
        let adsorptionChart, firstDerivativeChart, secondDerivativeChart, curvatureChart, curvatureDerivativeChart;
        let currentData = null;
        let markPoint = null;
        let calculationPoints = []; // 存储多个计算点
        
        // 初始化图表
        function initCharts() {
            // 等温吸附曲线图
            const adsorptionCtx = document.getElementById('adsorptionChart').getContext('2d');
            adsorptionChart = new Chart(adsorptionCtx, {
                type: 'scatter',
                data: {
                    datasets: [{
                        label: '等温吸附曲线',
                        backgroundColor: 'rgba(0, 0, 255, 0.8)', // 蓝色，20%透明度
                        borderColor: 'rgba(0, 0, 255, 0.8)',   // 蓝色，20%透明度
                        borderWidth: 1.5,
                        pointRadius: 2,
                        pointHoverRadius: 4,
                        showLine: true,
                        fill: false,
                        tension: 0,
                        animation: {
                            duration: 1000,
                            easing: 'easeInOutQuart'
                        }
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    animation: {
                        duration: 1000,
                        easing: 'easeInOutQuart'
                    },
                    plugins: {
                        title: {
                            display: true,
                            text: '朗缪尔等温吸附曲线',
                            font: {
                                size: 22,
                                weight: 'bold',
                                family: 'Times New Roman, serif',
                                color: '#000000' // 确保标题为黑色
                            },
                            padding: {
                                top: 5,
                                bottom: 10
                            }
                        },
                        legend: {
                            position: 'top',
                            labels: {
                                usePointStyle: true, // 使用点样式而非矩形
                                padding: 10,
                                font: {
                                    family: 'Times New Roman, serif',
                                    size: 16,
                                    color: '#000000' // 确保图例文字为黑色
                                }
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.95)',
                            titleColor: '#000',
                            bodyColor: '#000',
                            borderColor: '#000',
                            borderWidth: 1,
                            padding: 10,
                            cornerRadius: 8,
                            mode: 'point',
                            intersect: true,
                            callbacks: {
                                title: function(context) {
                                    // 返回数据集的标签作为标题，显示实际的点名称
                                    return context[0].dataset.label;
                                },
                                label: function(context) {
                                    return [
                                        `压力: ${context.parsed.x.toFixed(2)} MPa`,
                                        `吸附量: ${context.parsed.y.toFixed(4)} m³/t`
                                    ];
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            type: 'linear',
                            position: 'bottom',
                            title: {
                                display: true,
                                text: '压力 (MPa)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: '吸附量 (m³/t)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        }
                    },
                    interaction: {
                        intersect: false,
                        mode: 'index'
                    }
                }   
            });
            
            // 曲率导数图表
            const curvatureDerivativeCtx = document.getElementById('curvatureDerivativeChart').getContext('2d');
            curvatureDerivativeChart = new Chart(curvatureDerivativeCtx, {
                type: 'scatter',
                data: {
                    datasets: [{
                        label: '等温吸附曲率导数曲线',
                        backgroundColor: 'rgba(255, 0, 0, 0.8)', // 红色，20%透明度
                        borderColor: 'rgba(255, 0, 0, 0.8)',   // 红色，20%透明度
                        borderWidth: 1.5,
                        pointRadius: 2,
                        pointHoverRadius: 4,
                        showLine: true,
                        fill: false,
                        tension: 0,
                        animation: {
                            duration: 1000,
                            easing: 'easeInOutQuart'
                        }
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    animation: {
                        duration: 1000,
                        easing: 'easeInOutQuart'
                    },
                    plugins: {
                        title: {
                            display: true,
                            text: '等温吸附曲率导数曲线',
                            font: {
                                size: 22,
                                weight: 'bold',
                                family: 'Times New Roman, serif',
                                color: '#000000' // 确保标题为黑色
                            },
                            padding: {
                                top: 5,
                                bottom: 10
                            }
                        },
                        legend: {
                            position: 'top',
                            labels: {
                                usePointStyle: true, // 使用点样式而非矩形
                                padding: 10,
                                font: {
                                    family: 'Times New Roman, serif',
                                    size: 16,
                                    color: '#000000'
                                }
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.95)',
                            titleColor: '#000',
                            bodyColor: '#000',
                            borderColor: '#000',
                            borderWidth: 1,
                            padding: 10,
                            cornerRadius: 8,
                            mode: 'point',
                            intersect: true,
                            callbacks: {
                                title: function(context) {
                                    // 返回数据集的标签作为标题，显示实际的点名称
                                    return context[0].dataset.label;
                                },
                                label: function(context) {
                                    return [
                                        `压力: ${context.parsed.x.toFixed(2)} MPa`,
                                        `曲率导数值: ${context.parsed.y.toFixed(10)}`
                                    ];
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            type: 'linear',
                            position: 'bottom',
                            title: {
                                display: true,
                                text: '压力 (MPa)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: '曲率导数值 dK/dP',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        }
                    }
                }
            });
            
            // 一阶导数图表
            const firstDerivativeCtx = document.getElementById('firstDerivativeChart').getContext('2d');
            firstDerivativeChart = new Chart(firstDerivativeCtx, {
                type: 'scatter',
                data: {
                    datasets: [{
                        label: '等温吸附一阶导数曲线',
                        backgroundColor: 'rgba(0, 128, 0, 0.8)', // 绿色，20%透明度
                        borderColor: 'rgba(0, 128, 0, 0.8)',   // 绿色，20%透明度
                        borderWidth: 1.5,
                        pointRadius: 2,
                        pointHoverRadius: 4,
                        showLine: true,
                        fill: false,
                        tension: 0,
                        animation: {
                            duration: 1000,
                            easing: 'easeInOutQuart'
                        }
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    animation: {
                        duration: 1000,
                        easing: 'easeInOutQuart'
                    },
                    plugins: {
                        title: {
                            display: true,
                            text: '等温吸附一阶导数曲线',
                            font: {
                                size: 22,
                                weight: 'bold',
                                family: 'Times New Roman, serif',
                                color: '#000000' // 确保标题为黑色
                            },
                            padding: {
                                top: 5,
                                bottom: 10
                            }
                        },
                        legend: {
                            position: 'top',
                            labels: {
                                usePointStyle: true, // 使用点样式而非矩形
                                padding: 10,
                                font: {
                                    family: 'Times New Roman, serif',
                                    size: 16,
                                    color: '#000000'
                                }
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.95)',
                            titleColor: '#000',
                            bodyColor: '#000',
                            borderColor: '#000',
                            borderWidth: 1,
                            padding: 10,
                            cornerRadius: 8,
                            callbacks: {
                                title: function(context) {
                                    // 返回数据集的标签作为标题，显示实际的点名称
                                    return context[0].dataset.label;
                                },
                                label: function(context) {
                                    return [
                                        `压力: ${context.parsed.x.toFixed(2)} MPa`,
                                        `一阶导数: ${context.parsed.y.toFixed(6)}`
                                    ];
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            type: 'linear',
                            position: 'bottom',
                            title: {
                                display: true,
                                text: '压力 (MPa)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: '一阶导数 dV/dP',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        }
                    }
                }
            });
            
            // 二阶导数图表
            const secondDerivativeCtx = document.getElementById('secondDerivativeChart').getContext('2d');
            secondDerivativeChart = new Chart(secondDerivativeCtx, {
                type: 'scatter',
                data: {
                    datasets: [{
                        label: '等温吸附二阶导数曲线',
                        backgroundColor: 'rgba(255, 165, 0, 0.8)', // 橙色，20%透明度
                        borderColor: 'rgba(255, 165, 0, 0.8)',   // 橙色，20%透明度
                        borderWidth: 1.5,
                        pointRadius: 2,
                        pointHoverRadius: 4,
                        showLine: true,
                        fill: false,
                        tension: 0,
                        animation: {
                            duration: 1000,
                            easing: 'easeInOutQuart'
                        }
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    animation: {
                        duration: 1000,
                        easing: 'easeInOutQuart'
                    },
                    plugins: {
                        title: {
                            display: true,
                            text: '等温吸附二阶导数曲线',
                            font: {
                                size: 22,
                                weight: 'bold',
                                family: 'Times New Roman, serif',
                                color: '#000000' // 确保标题为黑色
                            },
                            padding: {
                                top: 5,
                                bottom: 10
                            }
                        },
                        legend: {
                            position: 'top',
                            labels: {
                                usePointStyle: true, // 使用点样式而非矩形
                                padding: 10,
                                font: {
                                    family: 'Times New Roman, serif',
                                    size: 16,
                                    color: '#000000'
                                }
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.95)',
                            titleColor: '#000',
                            bodyColor: '#000',
                            borderColor: '#000',
                            borderWidth: 1,
                            padding: 10,
                            cornerRadius: 8,
                            mode: 'point',
                            intersect: true,
                            callbacks: {
                                title: function(context) {
                                    // 返回数据集的标签作为标题，显示实际的点名称
                                    return context[0].dataset.label;
                                },
                                label: function(context) {
                                    return [
                                        `压力: ${context.parsed.x.toFixed(2)} MPa`,
                                        `二阶导数: ${context.parsed.y.toFixed(8)}`
                                    ];
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            type: 'linear',
                            position: 'bottom',
                            title: {
                                display: true,
                                text: '压力 (MPa)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: '二阶导数 d²V/dP²',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        }
                    }
                }
            });
            
            // 曲率图表
            const curvatureCtx = document.getElementById('curvatureChart').getContext('2d');
            curvatureChart = new Chart(curvatureCtx, {
                type: 'scatter',
                data: {
                    datasets: [{
                        label: '等温吸附曲率曲线',
                        backgroundColor: 'rgba(128, 0, 128, 0.8)', // 紫色，20%透明度
                        borderColor: 'rgba(128, 0, 128, 0.8)',   // 紫色，20%透明度
                        borderWidth: 1.5,
                        pointRadius: 2,
                        pointHoverRadius: 4,
                        showLine: true,
                        fill: false,
                        tension: 0,
                        animation: {
                            duration: 1000,
                            easing: 'easeInOutQuart'
                        }
                    }]
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    animation: {
                        duration: 1000,
                        easing: 'easeInOutQuart'
                    },
                    plugins: {
                        title: {
                            display: true,
                            text: '等温吸附曲率曲线',
                            font: {
                                size: 22,
                                weight: 'bold',
                                family: 'Times New Roman, serif',
                                color: '#000000' // 确保标题为黑色
                            },
                            padding: {
                                top: 5,
                                bottom: 10
                            }
                        },
                        legend: {
                            position: 'top',
                            labels: {
                                usePointStyle: true, // 使用点样式而非矩形
                                padding: 10,
                                font: {
                                    family: 'Times New Roman, serif',
                                    size: 16,
                                    color: '#000000'
                                }
                            }
                        },
                        tooltip: {
                            backgroundColor: 'rgba(255, 255, 255, 0.95)',
                            titleColor: '#000',
                            bodyColor: '#000',
                            borderColor: '#000',
                            borderWidth: 1,
                            padding: 10,
                            cornerRadius: 8,
                            mode: 'point',
                            intersect: true,
                            callbacks: {
                                title: function(context) {
                                    // 返回数据集的标签作为标题，显示实际的点名称
                                    return context[0].dataset.label;
                                },
                                label: function(context) {
                                    return [
                                        `压力: ${context.parsed.x.toFixed(2)} MPa`,
                                        `曲率值: ${context.parsed.y.toFixed(10)}`
                                    ];
                                }
                            }
                        }
                    },
                    scales: {
                        x: {
                            type: 'linear',
                            position: 'bottom',
                            title: {
                                display: true,
                                text: '压力 (MPa)',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        },
                        y: {
                            title: {
                                display: true,
                                text: '曲率值 K',
                                font: {
                                    size: 14,
                                    weight: 'bold',
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保轴标题为黑色
                                }
                            },
                            ticks: {
                                font: {
                                    family: 'Times New Roman, serif',
                                    color: '#000000' // 确保刻度标签为黑色
                                }
                            },
                            grid: {
                                color: 'rgba(0, 0, 0, 0.1)',
                                lineWidth: 1
                            },
                            border: {
                                color: '#000',
                                width: 1
                            }
                        }
                    }
                }
            });
        }
        
        // 生成曲线数据
        function generateCurves(VL, PL, minPressure = 0, maxPressure = 15, pointCount = 100) {
            const pressureData = [];
            const adsorptionData = [];
            const firstDerivativeData = [];
            const secondDerivativeData = [];
            const curvatureData = [];
            
            // 计算步长，根据用户需求，当输入数据点数量为10时，应该产生包括端点在内的11个数据点
            // 例如：0-10区间，pointCount=10将产生步长1，生成0,1,2,...,10共11个点
            const actualPointCount = pointCount + 1; // 实际数据点数量为用户输入加1
            const step = (maxPressure - minPressure) / pointCount; // 步长 = 区间长度 / 用户输入的数据点数量
            
            // 生成数据点，确保包含端点
            for (let i = 0; i < actualPointCount; i++) {
                const P = minPressure + i * step;
                
                // 计算吸附量 V
                const V = (VL * P) / (PL + P);
                
                // 计算一阶导数 dV/dP
                const dVdP = (VL * PL) / Math.pow(PL + P, 2);
                
                // 计算二阶导数 d²V/dP²
                const d2VdP2 = (-2 * VL * PL) / Math.pow(PL + P, 3);
                
                // 计算曲率 K = |d²V/dP²| / (1 + (dV/dP)²)^(3/2)
                const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
                
                pressureData.push(P);
                adsorptionData.push(V);
                firstDerivativeData.push(dVdP);
                secondDerivativeData.push(d2VdP2);
                curvatureData.push(curvature);
            }
            
            // 计算曲率导数 (使用中心差分法)
            const curvatureDerivativeData = [];
            for (let i = 0; i < actualPointCount; i++) {
                let dKdP;
                if (i === 0) {
                    // 前向差分
                    dKdP = (curvatureData[i + 1] - curvatureData[i]) / step;
                } else if (i === actualPointCount - 1) {
                    // 后向差分
                    dKdP = (curvatureData[i] - curvatureData[i - 1]) / step;
                } else {
                    // 中心差分
                    dKdP = (curvatureData[i + 1] - curvatureData[i - 1]) / (2 * step);
                }
                curvatureDerivativeData.push(dKdP);
            }
            
            // 计算特殊点 - 优化版，使用更可靠的算法
            const specialPoints = {};
            
            // 1. 启动压力：曲率导数首次达到最大值（使用更简单直接的方法）
            let maxCurvatureDerivative = -Infinity;
            let startPressureIndex = 0;
            // 简单地找到全局最大值
            for (let i = 0; i < actualPointCount; i++) {
                if (curvatureDerivativeData[i] > maxCurvatureDerivative) {
                    maxCurvatureDerivative = curvatureDerivativeData[i];
                    startPressureIndex = i;
                }
            }
            
            specialPoints.startPressure = {
                pressure: pressureData[startPressureIndex],
                curvature: curvatureData[startPressureIndex],
                curvatureDerivative: curvatureDerivativeData[startPressureIndex],
                index: startPressureIndex
            };
            
            // 2. 转折压力：曲率导数通过零点，曲率达到最大值
            // 找到曲率最大的点作为转折压力
            let maxCurvature = -Infinity;
            let transitionPressureIndex = 0;
            for (let i = 0; i < actualPointCount; i++) {
                if (curvatureData[i] > maxCurvature) {
                    maxCurvature = curvatureData[i];
                    transitionPressureIndex = i;
                }
            }
            
            specialPoints.transitionPressure = {
                pressure: pressureData[transitionPressureIndex],
                curvature: curvatureData[transitionPressureIndex],
                curvatureDerivative: curvatureDerivativeData[transitionPressureIndex],
                index: transitionPressureIndex
            };
            
            // 3. 敏感压力：曲率导数达到最小值
            let minCurvatureDerivative = Infinity;
            let sensitivePressureIndex = 0;
            for (let i = 0; i < actualPointCount; i++) {
                if (curvatureDerivativeData[i] < minCurvatureDerivative) {
                    minCurvatureDerivative = curvatureDerivativeData[i];
                    sensitivePressureIndex = i;
                }
            }
            
            specialPoints.sensitivePressure = {
                pressure: pressureData[sensitivePressureIndex],
                curvature: curvatureData[sensitivePressureIndex],
                curvatureDerivative: curvatureDerivativeData[sensitivePressureIndex],
                index: sensitivePressureIndex
            };
            
            return {
                pressure: pressureData,
                adsorption: adsorptionData,
                firstDerivative: firstDerivativeData,
                secondDerivative: secondDerivativeData,
                curvature: curvatureData,
                curvatureDerivative: curvatureDerivativeData,
                specialPoints: specialPoints
            };
        }
        
        // 更新图表
        function updateCharts(adsorptionData, firstDerivativeData, secondDerivativeData, curvatureData, curvatureDerivativeData, specialPoints = {}) {
            // 输出特殊点数据进行调试
            console.log('特殊点数据:', specialPoints);
            
            // 更新等温吸附曲线图表 - 直接使用原始数据
            adsorptionChart.data.datasets[0].data = adsorptionData;
            adsorptionChart.update();
            
            // 更新一阶导数图表 - 直接使用原始数据
            firstDerivativeChart.data.datasets[0].data = firstDerivativeData;
            firstDerivativeChart.update();
            
            // 更新二阶导数图表 - 直接使用原始数据
            secondDerivativeChart.data.datasets[0].data = secondDerivativeData;
            secondDerivativeChart.update();
            
            // 更新曲率图表 - 使用数据计算模块方式实现特殊点显示
            // 1. 保存原始曲线数据
            curvatureChart.data.datasets[0].data = curvatureData;
            
            // 2. 清除之前的数据集
            while (curvatureChart.data.datasets.length > 1) {
                curvatureChart.data.datasets.pop();
            }
            
            curvatureChart.update();
            
            // 更新曲率导数图表 - 使用数据计算模块方式实现特殊点显示
            // 1. 保存原始曲线数据
            curvatureDerivativeChart.data.datasets[0].data = curvatureDerivativeData;
            
            // 2. 清除之前的数据集
            while (curvatureDerivativeChart.data.datasets.length > 1) {
                curvatureDerivativeChart.data.datasets.pop();
            }
            
            curvatureDerivativeChart.update();
        }
        
        // 清除标记点 - 修改为清除所有标记点数据集
        function clearMarkPoint() {
            // 清除等温吸附曲线标记点 - 保留原始曲线数据集（索引0）
            if (adsorptionChart.data.datasets.length > 1) {
                adsorptionChart.data.datasets = [adsorptionChart.data.datasets[0]];
                adsorptionChart.update();
            }
            
            // 清除一阶导数曲线标记点 - 保留原始曲线数据集（索引0）
            if (firstDerivativeChart.data.datasets.length > 1) {
                firstDerivativeChart.data.datasets = [firstDerivativeChart.data.datasets[0]];
                firstDerivativeChart.update();
            }
            
            // 清除二阶导数曲线标记点 - 保留原始曲线数据集（索引0）
            if (secondDerivativeChart.data.datasets.length > 1) {
                secondDerivativeChart.data.datasets = [secondDerivativeChart.data.datasets[0]];
                secondDerivativeChart.update();
            }
            
            // 清除曲率曲线标记点 - 保留原始曲线数据集（索引0）
            if (curvatureChart.data.datasets.length > 1) {
                curvatureChart.data.datasets = [curvatureChart.data.datasets[0]];
                curvatureChart.update();
            }
            
            // 清除曲率导数曲线标记点 - 保留原始曲线数据集（索引0）
            if (curvatureDerivativeChart.data.datasets.length > 1) {
                curvatureDerivativeChart.data.datasets = [curvatureDerivativeChart.data.datasets[0]];
                curvatureDerivativeChart.update();
            }
            
            markPoint = null;
        }
        
        // 根据压力计算吸附量
        function calculateVolumeByPressure() {
            if (!currentData) {
                alert('请先生成曲线！');
                return null;
            }
            
            const inputPressure = parseFloat(document.getElementById('inputPressure').value);
            if (isNaN(inputPressure) || inputPressure < 0) {
                alert('请输入有效的压力值！');
                return null;
            }
            
            const VL = currentData.VL;
            const PL = currentData.PL;
            const V = (VL * inputPressure) / (PL + inputPressure);
            
            // 计算导数和曲率相关值
            const dVdP = (VL * PL) / Math.pow(PL + inputPressure, 2);
            const d2VdP2 = -2 * VL * PL / Math.pow(PL + inputPressure, 3);
            const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
            
            // 使用数值微分法计算曲率导数（与主曲线一致）
            const step = 0.01; // 使用一个小的步长进行数值微分
            
            // 在计算点附近生成三个点以应用中心差分
            const pPrev = inputPressure - step;
            const pNext = inputPressure + step;
            
            // 计算附近点的曲率
            const dVdPPrev = (VL * PL) / Math.pow(PL + pPrev, 2);
            const d2VdP2Prev = -2 * VL * PL / Math.pow(PL + pPrev, 3);
            const curvaturePrev = Math.abs(d2VdP2Prev) / Math.pow(1 + Math.pow(dVdPPrev, 2), 1.5);
            
            const dVdPNext = (VL * PL) / Math.pow(PL + pNext, 2);
            const d2VdP2Next = -2 * VL * PL / Math.pow(PL + pNext, 3);
            const curvatureNext = Math.abs(d2VdP2Next) / Math.pow(1 + Math.pow(dVdPNext, 2), 1.5);
            
            // 应用中心差分计算曲率导数
            const dKdP = (curvatureNext - curvaturePrev) / (2 * step);
            
            // 创建计算点对象，增加名称属性
            const calculationPoint = {
                id: Date.now(), // 使用时间戳作为唯一ID
                name: `计算点${calculationPoints.length + 1}`, // 默认名称
                pressure: inputPressure,
                volume: V,
                curvature: curvature,
                curvatureDerivative: dKdP
            };
            
            // 添加到计算点数组
            calculationPoints.push(calculationPoint);
            
            // 更新表格显示
            updateCalculationTable();
            
            // 在图表上标记点
            markPointOnCharts(inputPressure, V, calculationPoints.length - 1);
            
            return V;
        }
        
        // 根据吸附量计算压力
        function calculatePressureByVolume() {
            if (!currentData) {
                alert('请先生成曲线！');
                return null;
            }
            
            const inputVolume = parseFloat(document.getElementById('inputVolume').value);
            if (isNaN(inputVolume) || inputVolume < 0) {
                alert('请输入有效的吸附量值！');
                return null;
            }
            
            const VL = currentData.VL;
            const PL = currentData.PL;
            
            if (inputVolume >= VL) {
                alert('吸附量不能大于或等于兰氏体积！');
                return null;
            }
            
            const P = (PL * inputVolume) / (VL - inputVolume);
            
            // 计算导数和曲率相关值
            const dVdP = (VL * PL) / Math.pow(PL + P, 2);
            const d2VdP2 = -2 * VL * PL / Math.pow(PL + P, 3);
            const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
            
            // 使用数值微分法计算曲率导数（与主曲线一致）
            const step = 0.01; // 使用一个小的步长进行数值微分
            
            // 在计算点附近生成三个点以应用中心差分
            const pPrev = P - step;
            const pNext = P + step;
            
            // 计算附近点的曲率
            const dVdPPrev = (VL * PL) / Math.pow(PL + pPrev, 2);
            const d2VdP2Prev = -2 * VL * PL / Math.pow(PL + pPrev, 3);
            const curvaturePrev = Math.abs(d2VdP2Prev) / Math.pow(1 + Math.pow(dVdPPrev, 2), 1.5);
            
            const dVdPNext = (VL * PL) / Math.pow(PL + pNext, 2);
            const d2VdP2Next = -2 * VL * PL / Math.pow(PL + pNext, 3);
            const curvatureNext = Math.abs(d2VdP2Next) / Math.pow(1 + Math.pow(dVdPNext, 2), 1.5);
            
            // 应用中心差分计算曲率导数
            const dKdP = (curvatureNext - curvaturePrev) / (2 * step);
            
            // 创建计算点对象，增加名称属性
            const calculationPoint = {
                id: Date.now(), // 使用时间戳作为唯一ID
                name: `计算点${calculationPoints.length + 1}`, // 默认名称
                pressure: P,
                volume: inputVolume,
                curvature: curvature,
                curvatureDerivative: dKdP
            };
            
            // 添加到计算点数组
            calculationPoints.push(calculationPoint);
            
            // 更新表格显示
            updateCalculationTable();
            
            // 在图表上标记点
            markPointOnCharts(P, inputVolume, calculationPoints.length - 1);
            
            return P;
        }
        
        // 更新计算结果表格
        function updateCalculationTable() {
            const tableBody = document.getElementById('resultTableBody');
            tableBody.innerHTML = '';
            
            // 如果没有计算点，显示提示信息
            if (calculationPoints.length === 0) {
                const emptyRow = document.createElement('tr');
                emptyRow.innerHTML = '<td colspan="6" style="text-align: center; color: #999;">暂无计算结果</td>';
                tableBody.appendChild(emptyRow);
                return;
            }
            
            // 添加计算点到表格
            calculationPoints.forEach((point, index) => {
                // 确保点对象有hidden属性
                if (point.hidden === undefined) {
                    point.hidden = false;
                }
                
                const row = document.createElement('tr');
                
                // 直接应用行样式表示隐藏状态，不使用display:none
                if (point.hidden) {
                    row.style.backgroundColor = '#f5f5f5';
                    row.style.color = '#999';
                    row.classList.add('hidden-row');
                }
                
                row.innerHTML = `
                    <td style="text-align: center;"><input type="text" class="point-name" value="${point.name || `计算点${index + 1}`}" onchange="updatePointName(${point.id}, this.value)" style="width: 120px;"></td>
                    <td style="text-align: center;">${point.pressure.toFixed(2)}</td>
                    <td style="text-align: center;">${point.volume.toFixed(4)}</td>
                    <td style="text-align: center;">${point.curvature.toFixed(10)}</td>
                    <td style="text-align: center;">${point.curvatureDerivative ? point.curvatureDerivative.toFixed(10) : '0.0000000000'}</td>
                    <td style="text-align: center;">
                        <button class="toggle-btn" onclick="togglePointVisibility(${point.id}, this)" style="background-color: ${point.hidden ? '#ff9800' : '#4caf50'}; color: white;">${point.hidden ? '隐藏' : '显示'}</button>
                        <button class="delete-btn" onclick="deleteCalculationPoint(${point.id})">删除</button>
                    </td>
                `;
                tableBody.appendChild(row);
            });
        }
        
        // 切换计算点的可见性 - 暴露到全局作用域
        window.togglePointVisibility = function(id, button) {
            const point = calculationPoints.find(p => p.id === id);
            if (point) {
                // 切换隐藏状态
                point.hidden = !point.hidden;
                
                // 更新按钮文本 - 显示当前状态
                button.textContent = point.hidden ? '隐藏' : '显示';
                
                // 更新按钮背景颜色
                button.style.backgroundColor = point.hidden ? '#ff9800' : '#4caf50';
                button.style.color = 'white';
                
                // 使用closest方法直接获取当前行
                const row = button.closest('tr');
                
                // 改变行的样式为灰色表示隐藏
                if (point.hidden) {
                    row.style.backgroundColor = '#f5f5f5';
                    row.style.color = '#999';
                    // 给行添加一个hidden类便于识别
                    row.classList.add('hidden-row');
                } else {
                    // 恢复原始样式
                    row.style.backgroundColor = '';
                    row.style.color = '';
                    row.classList.remove('hidden-row');
                }
                
                // 更新图表显示
                updateMarkPointsVisibility();
            }
        };
        
        // 更新标记点的可见性
        function updateMarkPointsVisibility() {
            // 清除所有标记点
            clearMarkPoint();
            
            // 只添加非隐藏的计算点
            calculationPoints.forEach((point, index) => {
                if (!point.hidden) {
                    markPointOnCharts(point.pressure, point.volume, index);
                }
            });
        }
        
        // 更新计算点名称 - 暴露到全局作用域
        window.updatePointName = function(id, newName) {
            const point = calculationPoints.find(p => p.id === id);
            if (point) {
                point.name = newName;
                // 更新图表上的标签
                updateChartPointLabels();
            }
        };
        
        // 更新图表上的计算点标签
        function updateChartPointLabels() {
            // 更新等温吸附曲线图表
            updateChartDatasetLabels(adsorptionChart);
            // 更新一阶导数图表
            updateChartDatasetLabels(firstDerivativeChart);
            // 更新二阶导数图表
            updateChartDatasetLabels(secondDerivativeChart);
            // 更新曲率图表
            updateChartDatasetLabels(curvatureChart);
            // 更新曲率导数图表
            updateChartDatasetLabels(curvatureDerivativeChart);
        }
        
        // 更新单个图表的数据集标签
        function updateChartDatasetLabels(chart) {
            const datasets = chart.data.datasets;
            // 跳过第一个数据集（原始曲线）
            for (let i = 1; i < datasets.length; i++) {
                const dataset = datasets[i];
                // 尝试从标签中提取索引或查找匹配的点
                const pointIndex = parseInt(dataset.label.match(/\d+/)?.[0]) - 1;
                if (!isNaN(pointIndex) && pointIndex < calculationPoints.length) {
                    dataset.label = calculationPoints[pointIndex].name || `计算点${pointIndex + 1}`;
                }
            }
            chart.update();
        }
        
        // 删除单个计算点 - 暴露到全局作用域
        window.deleteCalculationPoint = function(id) {
            // 从数组中删除指定ID的计算点
            calculationPoints = calculationPoints.filter(point => point.id !== id);
            
            // 更新表格显示
            updateCalculationTable();
            
            // 清除所有标记点
            clearMarkPoint();
            
            // 重新绘制所有剩余的计算点
            if (calculationPoints.length > 0) {
                calculationPoints.forEach((point, index) => {
                    markPointOnCharts(point.pressure, point.volume, index);
                });
            }
        };
        
        // 清除所有计算结果
        function clearAllCalculations() {
            // 检查是否有临界解吸压力数据
            const hasCriticalPressurePoint = calculationPoints.some(point => point.name === '临界解吸压力');
            
            // 根据是否有临界解吸压力数据显示不同的确认消息
            let confirmMessage = '确定要清除所有计算结果吗？';
            if (hasCriticalPressurePoint) {
                confirmMessage = '确定要清除所有计算结果吗？临界解吸压力数据将被保留。如果删除后，需要再次点击生成曲线才能显示正确的校正点位。';
            } else {
                confirmMessage = '确定要清除所有计算结果吗？如果删除后，需要再次点击生成曲线才能显示正确的校正点位。';
            }
            
            // 显示确认对话框
            if (!confirm(confirmMessage)) {
                return; // 用户取消操作
            }
            
            // 只保留临界解吸压力数据
            calculationPoints = calculationPoints.filter(point => point.name === '临界解吸压力');
            
            // 更新表格显示
            updateCalculationTable();
            
            // 清除图表上的标记点
            clearMarkPoint();
            
            // 如果保留了临界解吸压力点，则重新在图表上标记它
            if (calculationPoints.length > 0) {
                calculationPoints.forEach((point, index) => {
                    markPointOnCharts(point.pressure, point.volume, index);
                });
            }
        }
        
        // 在图表上标记点 - 修改为支持多个不同颜色的标记点
        function markPointOnCharts(x, y, pointIndex = 0) {
            // 不再清除现有标记点，而是保留它们
            
            // 获取对应的计算点对象
            const point = calculationPoints[pointIndex];
            
            // 计算一阶和二阶导数值
            const VL = currentData.VL;
            const PL = currentData.PL;
            const dVdP = (VL * PL) / Math.pow(PL + x, 2);
            const d2VdP2 = -2 * VL * PL / Math.pow(PL + x, 3);
            const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
            
            // 计算曲率导数
            const denominator = Math.pow(PL + x, 4);
            const numerator = 6 * VL * PL * (PL + x);
            const d3VdP3 = numerator / denominator;
            const dKdP = Math.abs(d3VdP3 * Math.pow(1 + Math.pow(dVdP, 2), 1.5) - 
                              Math.abs(d2VdP2) * 1.5 * Math.pow(1 + Math.pow(dVdP, 2), 0.5) * 2 * dVdP * d2VdP2) / 
                         Math.pow(1 + Math.pow(dVdP, 2), 3);
            
            // 获取计算点名称，如果不存在则使用默认名称
            const pointName = point?.name || `计算点${pointIndex + 1}`;
            
            // 添加标记点数据集
            // 为不同的点生成不同的颜色
            const colors = [
                'rgba(255, 99, 132, 1)',    // 红色
                'rgba(54, 162, 235, 1)',    // 蓝色
                'rgba(255, 206, 86, 1)',    // 黄色
                'rgba(75, 192, 192, 1)',    // 绿色
                'rgba(153, 102, 255, 1)',   // 紫色
                'rgba(255, 159, 64, 1)',    // 橙色
                'rgba(199, 199, 199, 1)',   // 灰色
                'rgba(83, 102, 255, 1)',    // 靛蓝色
                'rgba(255, 99, 232, 1)',    // 粉色
                'rgba(99, 255, 132, 1)'     // 青绿色
            ];
            
            const colorIndex = pointIndex % colors.length;
            const pointColor = colors[colorIndex];
            const pointColorTransparent = pointColor.replace('1)', '0.7)');
            
            // 创建点数据集的配置
            const pointDatasetConfig = {
                label: pointName,
                backgroundColor: pointColor, // 使用不透明的颜色作为背景，确保图例显示为实心圆
                borderColor: 'rgba(0, 0, 0, 1)', // 增加黑色边框使其更突出
                borderWidth: 1.5, // 修改为1.5px宽度
                pointRadius: 8, // 增大点的大小，使其更突出
                pointHoverRadius: 10, // 增大悬停时的大小
                pointHoverBorderWidth: 1.5, // 修改为1.5px宽度
                pointStyle: 'circle', // 确保图例显示为圆形
                data: [{ x }],
                showLine: false, // 不显示连线，只显示点
                tension: 0,
                z: 200 // 确保计算点在最上层，高于特殊点
            };
            
            // 添加到等温吸附曲线图表
            const adsorptionDataset = { ...pointDatasetConfig, data: [{ x, y }] };
            adsorptionChart.data.datasets.push(adsorptionDataset);
            
            // 添加到一阶导数图表
            const firstDerivativeDataset = { ...pointDatasetConfig, data: [{ x, y: dVdP }] };
            firstDerivativeChart.data.datasets.push(firstDerivativeDataset);
            
            // 添加到二阶导数图表
            const secondDerivativeDataset = { ...pointDatasetConfig, data: [{ x, y: d2VdP2 }] };
            secondDerivativeChart.data.datasets.push(secondDerivativeDataset);
            
            // 添加到曲率图表
            const curvatureDataset = { ...pointDatasetConfig, data: [{ x, y: curvature }] };
            curvatureChart.data.datasets.push(curvatureDataset);
            
            // 添加到曲率导数图表 - 修复显示错误
            const curvatureDerivativeDataset = { 
                ...pointDatasetConfig, 
                data: [{ x, y: point && point.curvatureDerivative !== undefined ? point.curvatureDerivative : dKdP }]
            };
            curvatureDerivativeChart.data.datasets.push(curvatureDerivativeDataset);
            
            // 更新所有图表
            adsorptionChart.update();
            firstDerivativeChart.update();
            secondDerivativeChart.update();
            curvatureChart.update();
            curvatureDerivativeChart.update();
            
            // 保存标记点信息
            markPoint = { x, y, dVdP, d2VdP2, curvature, dKdP };
        }
        
        // 保存数据为本地文件
        function saveData() {
            if (!currentData) {
                document.getElementById('operationResult').innerHTML = 
                    `<div class="result-container error">
                        <strong>错误：</strong>没有可保存的数据！请先生成曲线。
                    </div>`;
                return;
            }
            
            try {
                // 创建currentData的深拷贝，避免直接修改原对象
                const dataToSave = JSON.parse(JSON.stringify(currentData));
                
                // 获取并保存含气量/临界解吸压力数据
                const gasContentInput = document.getElementById('gasContent');
                const criticalPressureInput = document.getElementById('criticalPressure');
                
                if (gasContentInput.style.display !== 'none') {
                    // 保存含气量
                    const gasContentValue = parseFloat(gasContentInput.value);
                    if (!isNaN(gasContentValue) && gasContentValue >= 0) {
                        dataToSave.gasContent = gasContentValue;
                    }
                } else {
                    // 保存临界解吸压力
                    const criticalPressureValue = parseFloat(criticalPressureInput.value);
                    if (!isNaN(criticalPressureValue) && criticalPressureValue >= 0) {
                        dataToSave.criticalPressure = criticalPressureValue;
                    }
                }
                
                // 创建JSON字符串
                const jsonContent = JSON.stringify(dataToSave, null, 2);
                
                // 创建Blob对象
                const blob = new Blob([jsonContent], { type: 'application/json;charset=utf-8;' });
                const url = URL.createObjectURL(blob);
                
                // 创建下载链接
                const link = document.createElement('a');
                link.setAttribute('href', url);
                link.setAttribute('download', `煤层气朗缪尔等温吸附数据_${currentData.blockName}_${currentData.coalSeam}_VL${currentData.VL}_PL${currentData.PL}.json`);
                link.style.visibility = 'hidden';
                
                // 添加到DOM并触发下载
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                
                // 释放URL对象
                URL.revokeObjectURL(url);
                
                // 显示保存成功消息
                document.getElementById('operationResult').innerHTML = 
                    `<div class="result-container success">
                        <strong>成功：</strong>数据已保存为本地文件！
                    </div>`;
            } catch (error) {
                document.getElementById('operationResult').innerHTML = 
                    `<div class="result-container error">
                        <strong>错误：</strong>数据保存失败！${error.message}
                    </div>`;
                console.error('保存数据失败:', error);
            }
        }
        
        // 添加关键压力点功能
        function addKeyPressurePoints() {
            // 自动展开数据计算模块，但只在折叠状态时才展开
            const content = document.getElementById('calculationContent');
            const toggleIcon = document.getElementById('calculationToggleIcon');
            
            // 检查模块是否处于折叠状态
            if (content && content.classList.contains('collapsed')) {
                // 只在折叠状态下才展开模块
                toggleIcon.click();
            }
            
            if (!currentData) {
                alert('请先生成曲线！');
                return;
            }
            
            // 检查是否已存在关键压力点（启动压力、转折压力、敏感压力）
            const hasKeyPoints = calculationPoints.some(point => 
                point.name === '启动压力' || 
                point.name === '转折压力' || 
                point.name === '敏感压力' ||
                point.name === '启动压力-校正' ||
                point.name === '转折压力-校正' ||
                point.name === '敏感压力-校正'
            );
            
            if (hasKeyPoints) {
                alert('关键压力点已存在，请先删除后再添加！');
                return;
            }
            
            // 生成曲线数据以获取特殊点
            const curvesData = generateCurves(
                currentData.VL, 
                currentData.PL, 
                0, 
                15, 
                100
            );
            
            const specialPoints = curvesData.specialPoints;
            
            // 查找临界解吸压力点，用于计算饱满系数
            const criticalPoint = calculationPoints.find(p => p.name === '临界解吸压力');
            const criticalVolume = criticalPoint ? criticalPoint.volume : 0; // 临界解吸压力对应的含气量
            const langmuirVolume = currentData && currentData.VL ? currentData.VL : 1; // 兰氏体积
            const saturationCoefficient = langmuirVolume > 0 ? criticalVolume / langmuirVolume : 0; // 饱满系数 = 临界解吸压力对应的含气量/兰氏体积
            
            // 计算曲率和曲率导数的辅助函数 - 使用数值微分（中心差分法）
            function calculateCurvatureAndDerivative(pressure) {
                const VL = currentData.VL;
                const PL = currentData.PL;
                
                // 定义步长，使用压力值的1%作为步长（自适应步长）
                const h = Math.max(0.0001, pressure * 0.01);
                
                // 吸附量函数
                function adsorption(p) {
                    return (VL * p) / (PL + p);
                }
                
                // 使用中心差分法计算一阶导数 dV/dP
                const dVdP = (adsorption(pressure + h) - adsorption(pressure - h)) / (2 * h);
                
                // 使用中心差分法计算二阶导数 d²V/dP²
                const d2VdP2 = (adsorption(pressure + h) - 2 * adsorption(pressure) + adsorption(pressure - h)) / (h * h);
                
                // 计算曲率 K = |d²V/dP²| / (1 + (dV/dP)²)^(3/2)
                const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
                
                // 计算曲率在P点的导数 dK/dP
                // 首先计算P+h和P-h处的曲率
                const dVdP_plus = (adsorption(pressure + 2*h) - adsorption(pressure)) / (2 * h);
                const dVdP_minus = (adsorption(pressure) - adsorption(pressure - 2*h)) / (2 * h);
                
                const d2VdP2_plus = (adsorption(pressure + 2*h) - 2 * adsorption(pressure + h) + adsorption(pressure)) / (h * h);
                const d2VdP2_minus = (adsorption(pressure) - 2 * adsorption(pressure - h) + adsorption(pressure - 2*h)) / (h * h);
                
                const curvature_plus = Math.abs(d2VdP2_plus) / Math.pow(1 + Math.pow(dVdP_plus, 2), 1.5);
                const curvature_minus = Math.abs(d2VdP2_minus) / Math.pow(1 + Math.pow(dVdP_minus, 2), 1.5);
                
                // 使用中心差分法计算曲率导数
                const curvatureDerivative = (curvature_plus - curvature_minus) / (2 * h);
                
                return { curvature, curvatureDerivative: Math.abs(curvatureDerivative) };
            }
            
            // 创建关键压力点对象并添加到计算点数组
            // 注意：交换了启动压力和敏感压力，因为它们被标反了
            const keyPoints = [
                {
                    id: Date.now() + 1,
                    name: '启动压力',
                    pressure: specialPoints.sensitivePressure.pressure,
                    volume: curvesData.adsorption[specialPoints.sensitivePressure.index],
                    curvature: specialPoints.sensitivePressure.curvature,
                    curvatureDerivative: specialPoints.sensitivePressure.curvatureDerivative
                },
                {
                    id: Date.now() + 2,
                    name: '转折压力',
                    pressure: specialPoints.transitionPressure.pressure,
                    volume: curvesData.adsorption[specialPoints.transitionPressure.index],
                    curvature: specialPoints.transitionPressure.curvature,
                    curvatureDerivative: specialPoints.transitionPressure.curvatureDerivative
                },
                {
                    id: Date.now() + 3,
                    name: '敏感压力',
                    pressure: specialPoints.startPressure.pressure,
                    volume: curvesData.adsorption[specialPoints.startPressure.index],
                    curvature: specialPoints.startPressure.curvature,
                    curvatureDerivative: specialPoints.startPressure.curvatureDerivative
                },
                // 添加校正压力点
                (() => {
                    const pressure = specialPoints.sensitivePressure.pressure * saturationCoefficient;
                    const volume = (currentData.VL * pressure) / (currentData.PL + pressure);
                    const { curvature, curvatureDerivative } = calculateCurvatureAndDerivative(pressure);
                    return {
                        id: Date.now() + 4,
                        name: '启动压力-校正',
                        pressure: pressure,
                        volume: volume,
                        curvature: curvature,
                        curvatureDerivative: curvatureDerivative
                    };
                })(),
                (() => {
                    const pressure = specialPoints.transitionPressure.pressure * saturationCoefficient;
                    const volume = (currentData.VL * pressure) / (currentData.PL + pressure);
                    const { curvature, curvatureDerivative } = calculateCurvatureAndDerivative(pressure);
                    return {
                        id: Date.now() + 5,
                        name: '转折压力-校正',
                        pressure: pressure,
                        volume: volume,
                        curvature: curvature,
                        curvatureDerivative: curvatureDerivative
                    };
                })(),
                (() => {
                    const pressure = specialPoints.startPressure.pressure * saturationCoefficient;
                    const volume = (currentData.VL * pressure) / (currentData.PL + pressure);
                    const { curvature, curvatureDerivative } = calculateCurvatureAndDerivative(pressure);
                    return {
                        id: Date.now() + 6,
                        name: '敏感压力-校正',
                        pressure: pressure,
                        volume: volume,
                        curvature: curvature,
                        curvatureDerivative: curvatureDerivative
                    };
                })()
            ];
            
            // 添加到计算点数组
            keyPoints.forEach(point => {
                calculationPoints.push(point);
            });
            
            // 更新表格显示
            updateCalculationTable();
            
            // 清除现有标记点
            clearMarkPoint();
            
            // 重新添加所有计算点（包括临界解吸压力点和新添加的关键压力点）
            calculationPoints.forEach((point, index) => {
                markPointOnCharts(point.pressure, point.volume, index);
            });
            
            // 显示成功消息
            document.getElementById('operationResult').innerHTML = 
                `<div class="result-container success">
                    <strong>成功：</strong>已添加启动压力、转折压力、敏感压力及其校正压力计算点！
                </div>`;
            
            // 3秒后自动清除消息
            setTimeout(() => {
                document.getElementById('operationResult').innerHTML = '';
            }, 3000);
        }
        
        // 暴露关键压力点功能到全局作用域
        window.addKeyPressurePoints = addKeyPressurePoints;
        
        // 加载本地数据文件
        function loadData() {
            // 创建文件输入元素
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.json';
            
            // 获取进度条元素
            const progressBarContainer = document.getElementById('progressBarContainer');
            const progressBar = document.getElementById('progressBar');
            const operationResult = document.getElementById('operationResult');
            
            // 重置结果区域
            operationResult.innerHTML = '';
            
            // 文件选择事件
            input.onchange = function(event) {
                const file = event.target.files[0];
                if (!file) return;
                
                // 显示进度条，初始值为10%
                progressBarContainer.style.display = 'block';
                progressBar.style.width = '10%';
                
                const reader = new FileReader();
                
                reader.onloadstart = function() {
                    // 文件开始读取
                    progressBar.style.width = '30%';
                };
                
                reader.onprogress = function(e) {
                    if (e.lengthComputable) {
                        const percentLoaded = Math.round((e.loaded / e.total) * 100);
                        // 读取文件进度(30%-60%)
                        progressBar.style.width = `${30 + percentLoaded * 0.3}%`;
                    }
                };
                
                reader.onload = function(e) {
                    // 文件读取完成，解析数据(60%-70%)
                    progressBar.style.width = '70%';
                    
                    try {
                        const loadedData = JSON.parse(e.target.result);
                        
                        // 验证数据格式(70%-80%)
                        progressBar.style.width = '80%';
                        
                        if (!loadedData.VL || !loadedData.PL || !loadedData.adsorptionData) {
                            throw new Error('无效的数据格式！');
                        }
                        
                        // 设置当前数据
                        currentData = loadedData;
                        
                        // 填充表单(80%-90%)
                        progressBar.style.width = '90%';
                        
                        document.getElementById('blockName').value = loadedData.blockName || '';
                        document.getElementById('coalSeam').value = loadedData.coalSeam || '';
                        document.getElementById('langmuirVolume').value = loadedData.VL;
                        document.getElementById('langmuirPressure').value = loadedData.PL;
                        document.getElementById('minPressure').value = loadedData.minPressure || 0;
                        document.getElementById('maxPressure').value = loadedData.maxPressure || 50;
                        document.getElementById('pressureInterval').value = loadedData.pressureInterval || 0.5;
                        document.getElementById('pointCount').value = loadedData.pointCount || 200;
                        
                        // 加载含气量/临界解吸压力数据
                        const gasContentInput = document.getElementById('gasContent');
                        const criticalPressureInput = document.getElementById('criticalPressure');
                        let hasGasContentOrCriticalPressure = false;
                        
                        if (loadedData.gasContent !== undefined) {
                            // 如果有含气量数据，显示含气量输入框并填充值
                            gasContentInput.style.display = 'block';
                            criticalPressureInput.style.display = 'none';
                            gasContentInput.value = loadedData.gasContent;
                            document.getElementById('gasContentLabel').textContent = '含气量 (m³/t)';
                            
                            // 标记有含气量/临界解吸压力数据
                            hasGasContentOrCriticalPressure = true;
                        } else if (loadedData.criticalPressure !== undefined) {
                            // 如果有临界解吸压力数据，显示临界解吸压力输入框并填充值
                            gasContentInput.style.display = 'none';
                            criticalPressureInput.style.display = 'block';
                            criticalPressureInput.value = loadedData.criticalPressure;
                            document.getElementById('gasContentLabel').textContent = '临界解吸压力 (MPa)';
                            
                            // 标记有含气量/临界解吸压力数据
                            hasGasContentOrCriticalPressure = true;
                        }
                        // 更新图表(90%-95%)
                        progressBar.style.width = '95%';
                        
                        updateCharts(
                            loadedData.adsorptionData,
                            loadedData.firstDerivativeData,
                            loadedData.secondDerivativeData,
                            loadedData.curvatureData,
                            loadedData.curvatureDerivativeData || [],
                            loadedData.specialPoints || {}
                        );
                        
                        // 设置图表标题和轴范围(95%-100%)
                        setTimeout(() => {
                            progressBar.style.width = '100%';
                            
                            // 设置图表标题
                            const titleText = `朗缪尔等温吸附曲线-${loadedData.blockName || ''}${loadedData.coalSeam ? ' '+loadedData.coalSeam : ''}`;
            adsorptionChart.options.plugins.title.text = titleText;
            firstDerivativeChart.options.plugins.title.text = `等温吸附一阶导数曲线-${loadedData.blockName || ''}${loadedData.coalSeam ? ' '+loadedData.coalSeam : ''}`;
            secondDerivativeChart.options.plugins.title.text = `等温吸附二阶导数曲线-${loadedData.blockName || ''}${loadedData.coalSeam ? ' '+loadedData.coalSeam : ''}`;
            curvatureChart.options.plugins.title.text = `等温吸附曲率曲线-${loadedData.blockName || ''}${loadedData.coalSeam ? ' '+loadedData.coalSeam : ''}`;
            curvatureDerivativeChart.options.plugins.title.text = `等温吸附曲率导数曲线-${loadedData.blockName || ''}${loadedData.coalSeam ? ' '+loadedData.coalSeam : ''}`;
                            
                            // 设置x轴范围
                            const minPressure = loadedData.minPressure || 0;
                            const maxPressure = loadedData.maxPressure || 50;
                            const pressureInterval = loadedData.pressureInterval || 0.5;
                            [adsorptionChart, firstDerivativeChart, secondDerivativeChart, curvatureChart, curvatureDerivativeChart].forEach(chart => {
                                chart.options.scales.x.min = minPressure;
                                chart.options.scales.x.max = maxPressure;
                                chart.options.scales.x.ticks.stepSize = pressureInterval;
                                chart.update();
                            });
                            
                            // 清除标记点
                            clearMarkPoint();
                            
                            // 如果有含气量/临界解吸压力数据，延迟添加临界解吸压力计算点
                            if (hasGasContentOrCriticalPressure) {
                                setTimeout(() => {
                                    // 检查是否有有效的输入值
                                    if (gasContentInput.style.display !== 'none' && gasContentInput.value) {
                                        handleGasContentOrCriticalPressureChange();
                                    } else if (criticalPressureInput.style.display !== 'none' && criticalPressureInput.value) {
                                        handleGasContentOrCriticalPressureChange();
                                    }
                                }, 200);
                            }
                            
                            // 显示加载成功消息
                            operationResult.innerHTML = 
                                `<div class="result-container success">
                                    <strong>成功：</strong>数据加载成功！
                                </div>`;
                            
                            // 延迟隐藏进度条
                            setTimeout(() => {
                                progressBarContainer.style.display = 'none';
                                progressBar.style.width = '0%';
                            }, 500);
                        }, 300);
                    } catch (error) {
                        operationResult.innerHTML = 
                            `<div class="result-container error">
                                <strong>错误：</strong>数据加载失败！${error.message}
                            </div>`;
                        console.error('加载数据失败:', error);
                        
                        // 错误时隐藏进度条
                        setTimeout(() => {
                            progressBarContainer.style.display = 'none';
                            progressBar.style.width = '0%';
                        }, 500);
                    }
                };
                
                reader.onerror = function() {
                    operationResult.innerHTML = 
                        `<div class="result-container error">
                            <strong>错误：</strong>文件读取失败！
                        </div>`;
                    
                    // 错误时隐藏进度条
                    setTimeout(() => {
                        progressBarContainer.style.display = 'none';
                        progressBar.style.width = '0%';
                    }, 500);
                };
                
                reader.readAsText(file);
            };
            
            // 触发文件选择对话框
            input.click();
        }
        
        // 导出数据 - 打开弹窗
        function exportData() {
            if (!currentData || !currentData.adsorptionData) {
                alert('没有可导出的数据！请先生成曲线。');
                return;
            }
            
            // 显示导出弹窗
            document.getElementById('exportModal').style.display = 'flex';
        }
        
        // 关闭导出弹窗
        function closeExportModal() {
            document.getElementById('exportModal').style.display = 'none';
        }
        
        // 导出Excel (CSV)格式
        function exportExcel() {
            if (!currentData || !currentData.adsorptionData) {
                alert('没有可导出的数据！');
                closeExportModal();
                return;
            }
            
            // 构建CSV内容，添加UTF-8 BOM以确保Excel正确识别中文
            let csvContent = '\ufeff压力(MPa),吸附量(m³/t),一阶导数(dV/dP),二阶导数(d²V/dP²),曲率值(K),曲率导数(dK/dP)\n';
            
            // 添加数据行
            for (let i = 0; i < currentData.adsorptionData.length; i++) {
                const P = currentData.adsorptionData[i].x.toFixed(4);
                const V = currentData.adsorptionData[i].y.toFixed(4);
                const dVdP = currentData.firstDerivativeData[i]?.y?.toFixed(8) || '';
                const d2VdP2 = currentData.secondDerivativeData[i]?.y?.toFixed(10) || '';
                const curvature = currentData.curvatureData[i]?.y?.toFixed(12) || '';
                const curvatureDerivative = currentData.curvatureDerivativeData?.[i]?.y?.toFixed(14) || '';
                
                csvContent += `${P},${V},${dVdP},${d2VdP2},${curvature},${curvatureDerivative}\n`;
            }
        
            // 创建Blob对象
            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            
            // 创建下载链接
            const link = document.createElement('a');
            link.setAttribute('href', url);
            link.setAttribute('download', `煤层气朗缪尔等温吸附数据_${currentData.blockName}_${currentData.coalSeam}_VL${currentData.VL}_PL${currentData.PL}.csv`);
            link.style.visibility = 'hidden';
            
            // 添加到DOM并触发下载
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            
            // 释放URL对象
            URL.revokeObjectURL(url);
            
            // 显示导出成功消息
            document.getElementById('operationResult').innerHTML = 
                `<div class="result-container success">
                    <strong>成功：</strong>Excel数据导出成功！
                </div>`;
            
            // 关闭弹窗
            closeExportModal();
        }
        
        // 保存图像
        function saveImage() {
            if (!currentData) {
                alert('没有可保存的图像！请先生成曲线。');
                return;
            }
            
            // 创建一个临时canvas来合并所有图表
            const tempCanvas = document.createElement('canvas');
            const ctx = tempCanvas.getContext('2d');
            
            // 设置临时canvas的尺寸（五个图表垂直排列，增加边距）
            const chartWidth = 1000;
            const chartHeight = 600;
            const margin = 100; // 增大上边距
            const bottomMargin = 80; // 增加底部边距，避免时间戳与X轴标签重合
            const padding = 40; // 增加图表间距，避免标题与上一个图表的x轴标签重叠
            // 检查是否有关键压力点，以便调整canvas高度
            const hasKeyPoints = calculationPoints.some(point => 
                point.name === '启动压力' || 
                point.name === '转折压力' || 
                point.name === '敏感压力'
            );
            // 如果有关键压力点，增加canvas高度
            const keyPointsHeight = hasKeyPoints ? 40 : 0;
            tempCanvas.width = chartWidth;
            tempCanvas.height = margin + chartHeight * 5 + padding * 4 + bottomMargin + keyPointsHeight;
            
            // 绘制背景
            ctx.fillStyle = '#ffffff';
            ctx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
            
            // 获取各个图表的图像数据（包括曲率导数图表）
            const adsorptionImage = adsorptionChart.toBase64Image();
            const firstDerivativeImage = firstDerivativeChart.toBase64Image();
            const secondDerivativeImage = secondDerivativeChart.toBase64Image();
            const curvatureImage = curvatureChart.toBase64Image();
            const curvatureDerivativeImage = curvatureDerivativeChart.toBase64Image();
            
            // 创建图像对象并绘制到临时canvas
            let imagesLoaded = 0;
            const totalImages = 5; // 更新为5个图表
            
            // 图像加载完成后绘制
            function onImageLoaded(index, img) {
                // 第一个图表需要与标题保持一定距离，根据是否有关键压力点调整偏移量
                const firstChartOffset = hasKeyPoints ? 80 : 40; // 增大关键压力点存在时的偏移量
                const yOffset = margin + firstChartOffset + index * (chartHeight + padding);
                ctx.drawImage(img, 0, yOffset, chartWidth, chartHeight);
                imagesLoaded++;
                
                // 所有图像加载完成后保存
                if (imagesLoaded === totalImages) {
                    // 添加标题 - 改进字体和样式，增大字号并调整间距
                    ctx.fillStyle = '#000000';
                    ctx.font = 'bold 30px Microsoft YaHei, SimSun, serif';
                    ctx.textAlign = 'center';
                    ctx.fillText(
                        `煤层气朗缪尔等温吸附曲线分析`,
                        tempCanvas.width / 2,
                        margin - 40
                    );
                    
                    // 添加参数信息 - 改进布局，增大字号并调整间距
                    ctx.font = '22px Microsoft YaHei, SimSun, serif';
                    let paramInfo = `${currentData.blockName} ${currentData.coalSeam} - VL = ${currentData.VL} m³/t, PL = ${currentData.PL} MPa`;
                    
                    // 添加含气量/临界解吸压力数据
                    if (currentData.gasContent) {
                        paramInfo += `, 含气量 = ${currentData.gasContent} m³/t`;
                    } else if (currentData.criticalPressure) {
                        paramInfo += `, 临界解吸压力 = ${currentData.criticalPressure} MPa`;
                    }
                    
                    ctx.fillText(paramInfo, tempCanvas.width / 2, margin + 20);
                    
                    // 添加关键压力点信息
                    if (hasKeyPoints) {
                        // 获取关键压力点
                        const startPoint = calculationPoints.find(p => p.name === '启动压力');
                        const transitionPoint = calculationPoints.find(p => p.name === '转折压力');
                        const sensitivePoint = calculationPoints.find(p => p.name === '敏感压力');
                        const criticalPoint = calculationPoints.find(p => p.name === '临界解析压力');
                        
                        // 计算校正压力
                        const criticalVolume = criticalPoint ? criticalPoint.volume : (currentData.gasContent || 0); // 临界解吸压力对应的含气量
                        const langmuirVolume = currentData && currentData.VL ? currentData.VL : 1; // 兰氏体积
                        const saturationCoefficient = langmuirVolume > 0 ? criticalVolume / langmuirVolume : 0; // 饱满系数 = 临界解吸压力对应的含气量/兰氏体积
                        
                        // 格式化压力显示，包含校正压力
                        const formatPressureWithCorrection = (point) => {
                            if (!point) return 'N/A';
                            const correctedPressure = (point.pressure * saturationCoefficient).toFixed(2);
                            return `${point.pressure.toFixed(2)}(${correctedPressure})`;
                        };
                        
                        // 格式化临界解吸压力显示
                        const formatCriticalPressure = () => {
                            // 优先从currentData获取临界解吸压力值
                            if (currentData && currentData.criticalPressure) {
                                return currentData.criticalPressure.toFixed(2);
                            }
                            // 如果criticalPoint存在，也可以从这里获取
                            if (criticalPoint && criticalPoint.pressure) {
                                return criticalPoint.pressure.toFixed(2);
                            }
                            return 'N/A';
                        };
                        
                        // 显示关键压力点信息
                        ctx.font = '18px Microsoft YaHei, SimSun, serif';
                        ctx.fillText(
                            `CDP: ${formatCriticalPressure()} MPa, 启动压力: ${formatPressureWithCorrection(startPoint)} MPa, 转折压力: ${formatPressureWithCorrection(transitionPoint)} MPa, 敏感压力: ${formatPressureWithCorrection(sensitivePoint)} MPa`,
                            tempCanvas.width / 2,
                            margin + 50 // 在参数信息下方留出一定距离
                        );
                    }
                    
                    // 添加时间戳
                    ctx.font = '14px Microsoft YaHei, SimSun, sans-serif';
                    ctx.fillStyle = '#666666';
                    const currentTime = new Date().toLocaleString('zh-CN');
                    ctx.fillText(
                        `生成时间: ${currentTime}`,
                        tempCanvas.width / 2,
                        tempCanvas.height - 20
                    );
                    
                    // 保存为PNG图像
                    const link = document.createElement('a');
                    link.download = `煤层气朗缪尔等温吸附曲线_${currentData.blockName}_${currentData.coalSeam}_VL${currentData.VL}_PL${currentData.PL}.png`;
                    link.href = tempCanvas.toDataURL('image/png');
                    
                    // 添加下载完成的提示
                    link.onclick = function() {
                        setTimeout(() => {
                            document.getElementById('operationResult').innerHTML = 
                                `<div class="result-container success">
                                    <strong>成功：</strong>图像保存成功！已包含所有五个图表。
                                </div>`;
                        }, 100);
                    };
                    
                    link.click();
                }
            }
            
            // 加载并绘制各个图表图像（添加曲率导数图表）
            const imageSources = [adsorptionImage, firstDerivativeImage, secondDerivativeImage, curvatureImage, curvatureDerivativeImage];
            imageSources.forEach((src, index) => {
                const img = new Image();
                img.onload = () => onImageLoaded(index, img);
                img.onerror = () => {
                    alert(`加载图表图像失败，索引：${index}`);
                };
                img.src = src;
            });
        }
        
        // 事件监听
        // DOM 加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 初始化图表
            initCharts();
            
            // 生成曲线按钮点击事件
            document.getElementById('generateBtn').addEventListener('click', function() {
                const blockName = document.getElementById('blockName').value;
                const coalSeam = document.getElementById('coalSeam').value;
                const VL = parseFloat(document.getElementById('langmuirVolume').value);
                const PL = parseFloat(document.getElementById('langmuirPressure').value);
                
                // 获取压力范围设置
                const minPressure = parseFloat(document.getElementById('minPressure').value);
                const maxPressure = parseFloat(document.getElementById('maxPressure').value);
                const pressureInterval = parseFloat(document.getElementById('pressureInterval').value);
                let pointCount = parseInt(document.getElementById('pointCount').value);
                
                // 验证输入
                if (!blockName || !coalSeam || isNaN(VL) || isNaN(PL) || VL <= 0 || PL <= 0) {
                    alert('请输入有效的基础参数！');
                    return;
                }
                
                // 验证压力范围设置
                if (isNaN(minPressure) || isNaN(maxPressure) || isNaN(pressureInterval) || minPressure < 0 || maxPressure <= minPressure || pressureInterval <= 0) {
                    alert('请输入有效的压力范围参数！');
                    return;
                }
                
                // 计算曲线数据
                const curvesData = generateCurves(VL, PL, minPressure, maxPressure, pointCount);
                
                // 转换为图表需要的格式
                const adsorptionData = curvesData.pressure.map((P, index) => ({ x: P, y: curvesData.adsorption[index] }));
                const firstDerivativeData = curvesData.pressure.map((P, index) => ({ x: P, y: curvesData.firstDerivative[index] }));
                const secondDerivativeData = curvesData.pressure.map((P, index) => ({ x: P, y: curvesData.secondDerivative[index] }));
                const curvatureData = curvesData.pressure.map((P, index) => ({ x: P, y: curvesData.curvature[index] }));
                const curvatureDerivativeData = curvesData.pressure.map((P, index) => ({ x: P, y: curvesData.curvatureDerivative[index] }));
                
                // 保存当前数据
                currentData = {
                    blockName,
                    coalSeam,
                    VL,
                    PL,
                    minPressure,
                    maxPressure,
                    pressureInterval,
                    pointCount,
                    adsorptionData,
                    firstDerivativeData,
                    secondDerivativeData,
                    curvatureData,
                    curvatureDerivativeData,
                    specialPoints: curvesData.specialPoints
                };
                
                // 更新图表前先删除所有计算点
                calculationPoints = [];
                clearMarkPoint();
                updateCalculationTable();
                
                // 更新图表
                updateCharts(adsorptionData, firstDerivativeData, secondDerivativeData, curvatureData, curvatureDerivativeData, curvesData.specialPoints);
                
                // 设置图表标题
                const titleText = `朗缪尔等温吸附曲线-${blockName}${coalSeam ? ' '+coalSeam : ''}`;
                adsorptionChart.options.plugins.title.text = titleText;
                firstDerivativeChart.options.plugins.title.text = `等温吸附一阶导数曲线-${blockName}${coalSeam ? ' '+coalSeam : ''}`;
                secondDerivativeChart.options.plugins.title.text = `等温吸附二阶导数曲线-${blockName}${coalSeam ? ' '+coalSeam : ''}`;
                curvatureChart.options.plugins.title.text = `等温吸附曲率曲线-${blockName}${coalSeam ? ' '+coalSeam : ''}`;
                curvatureDerivativeChart.options.plugins.title.text = `等温吸附曲率导数曲线-${blockName}${coalSeam ? ' '+coalSeam : ''}`;
                
                // 显示曲线生成成功提示
                document.getElementById('operationResult').innerHTML = 
                    `<div class="result-container success">
                        <strong>成功：</strong>曲线生成成功！
                    </div>`;
                
                // 设置x轴范围
                [adsorptionChart, firstDerivativeChart, secondDerivativeChart, curvatureChart, curvatureDerivativeChart].forEach(chart => {
                    chart.options.scales.x.min = minPressure;
                    chart.options.scales.x.max = maxPressure;
                    chart.options.scales.x.ticks.stepSize = pressureInterval;
                    chart.update();
                });
                
                // 清除标记点
                clearMarkPoint();
                
                // 自动检查并处理含气量/临界解吸压力输入
                // 检查是否有有效的输入数据
                const gasContentInput = document.getElementById('gasContent');
                const criticalPressureInput = document.getElementById('criticalPressure');
                
                // 检查是否有有效的输入值
                if (gasContentInput.style.display !== 'none') {
                    // 含气量输入框可见
                    const gasContentValue = parseFloat(gasContentInput.value);
                    if (!isNaN(gasContentValue) && gasContentValue > 0 && gasContentValue < VL) {
                        // 调用处理函数添加临界解吸压力计算点
                        handleGasContentOrCriticalPressureChange();
                    }
                } else {
                    // 临界解吸压力输入框可见
                    const criticalPressureValue = parseFloat(criticalPressureInput.value);
                    if (!isNaN(criticalPressureValue) && criticalPressureValue > 0) {
                        // 调用处理函数添加临界解析压力计算点
                        handleGasContentOrCriticalPressureChange();
                    }
                }
            });
            
            // 保存数据按钮点击事件
            document.getElementById('saveDataBtn').addEventListener('click', saveData);
            
            // 添加关键压力点按钮点击事件
            document.getElementById('addKeyPointsBtn').addEventListener('click', addKeyPressurePoints);
            
            // 加载数据按钮点击事件
            document.getElementById('loadDataBtn').addEventListener('click', loadData);
            
            // 导出数据按钮点击事件
            document.getElementById('exportDataBtn').addEventListener('click', exportData);
            
            // 保存图像按钮点击事件
            document.getElementById('saveImageBtn').addEventListener('click', saveImage);
            
            // 吸附量和压力互算功能
            document.getElementById('calcByPressure').addEventListener('click', calculateVolumeByPressure);
            document.getElementById('calcByVolume').addEventListener('click', calculatePressureByVolume);
            
            // 清除计算结果按钮点击事件
            document.getElementById('clearCalculationBtn').addEventListener('click', clearAllCalculations);
            
            // 初始化计算结果表格
            updateCalculationTable();
        });
        
        // 公式说明模块收缩功能
        function toggleFormulaSection() {
            const content = document.getElementById('formulaContent');
            const icon = document.getElementById('formulaToggleIcon');
            
            if (content.classList.contains('collapsed')) {
                // 展开
                content.classList.remove('collapsed');
                icon.classList.add('open');
                content.style.maxHeight = content.scrollHeight + 'px';
                
                // 在下一个渲染周期调整高度
                setTimeout(() => {
                    content.style.maxHeight = 'none';
                }, 300);
            } else {
                // 收起
                content.style.maxHeight = content.scrollHeight + 'px';
                setTimeout(() => {
                    content.classList.add('collapsed');
                    icon.classList.remove('open');
                    content.style.maxHeight = null;
                }, 10);
            }
        }
        
        // 图表区域收缩功能
        function toggleChartSection(containerId) {
            const content = document.getElementById(containerId);
            const icon = content.previousElementSibling.querySelector('.toggle-icon');
            
            if (content.classList.contains('collapsed')) {
                // 展开
                content.classList.remove('collapsed');
                icon.classList.add('open');
                content.style.maxHeight = content.scrollHeight + 'px';
                
                // 在下一个渲染周期调整高度
                setTimeout(() => {
                    content.style.maxHeight = 'none';
                }, 300);
            } else {
                // 收起
                content.style.maxHeight = content.scrollHeight + 'px';
                setTimeout(() => {
                    content.classList.add('collapsed');
                    icon.classList.remove('open');
                    content.style.maxHeight = null;
                }, 10);
            }
        }
        
        // 数据计算模块收缩功能
        function toggleCalculationSection() {
            const content = document.getElementById('calculationContent');
            const icon = document.getElementById('calculationToggleIcon');
            
            if (content.classList.contains('collapsed')) {
                // 展开
                content.classList.remove('collapsed');
                icon.classList.add('open');
                content.style.maxHeight = content.scrollHeight + 'px';
                
                // 在下一个渲染周期调整高度
                setTimeout(() => {
                    content.style.maxHeight = 'none';
                }, 300);
            } else {
                // 收起
                content.style.maxHeight = content.scrollHeight + 'px';
                setTimeout(() => {
                    content.classList.add('collapsed');
                    icon.classList.remove('open');
                    content.style.maxHeight = null;
                }, 10);
            }
        }
        
        // 切换临界解吸压力输入显示
        function toggleCriticalPressure(event) {
            event.preventDefault(); // 阻止右键菜单
            
            const label = document.getElementById('gasContentLabel');
            const gasContentInput = document.getElementById('gasContent');
            const criticalPressureInput = document.getElementById('criticalPressure');
            
            // 切换显示状态
            if (gasContentInput.style.display !== 'none') {
                // 切换到临界解吸压力
                label.textContent = '临界解吸压力 (MPa)';
                gasContentInput.style.display = 'none';
                criticalPressureInput.style.display = 'block';
            } else {
                // 切换回含气量
                label.textContent = '含气量 (m³/t)';
                gasContentInput.style.display = 'block';
                criticalPressureInput.style.display = 'none';
            }
        }
        
        // 当含气量或临界解吸压力输入变化时，添加临界解吸压力计算点
        function handleGasContentOrCriticalPressureChange() {
            if (!currentData) return; // 如果没有生成曲线，不执行
            
            const gasContentInput = document.getElementById('gasContent');
            const criticalPressureInput = document.getElementById('criticalPressure');
            const VL = currentData.VL;
            const PL = currentData.PL;
            
            let pressure, volume;
            
            // 检查哪个输入框可见
            if (gasContentInput.style.display !== 'none') {
                // 含气量输入框可见
                const gasContentValue = parseFloat(gasContentInput.value);
                if (isNaN(gasContentValue) || gasContentValue < 0) return;
                
                // 吸附量 = 含气量
                volume = gasContentValue;
                
                // 压力通过等温吸附公式反算
                if (volume >= VL) return; // 吸附量不能大于或等于兰氏体积
                pressure = (PL * volume) / (VL - volume);
            } else {
                // 临界解析压力输入框可见
                const criticalPressureValue = parseFloat(criticalPressureInput.value);
                if (isNaN(criticalPressureValue) || criticalPressureValue < 0) return;
                
                // 压力 = 临界解吸压力
                pressure = criticalPressureValue;
                
                // 吸附量通过等温吸附公式反算
                volume = (VL * pressure) / (PL + pressure);
            }
            
            // 计算导数和曲率相关值
            const dVdP = (VL * PL) / Math.pow(PL + pressure, 2);
            const d2VdP2 = -2 * VL * PL / Math.pow(PL + pressure, 3);
            const curvature = Math.abs(d2VdP2) / Math.pow(1 + Math.pow(dVdP, 2), 1.5);
            
            // 使用数值微分法计算曲率导数
            const step = 0.01;
            const pPrev = pressure - step;
            const pNext = pressure + step;
            
            // 计算附近点的曲率
            const dVdPPrev = (VL * PL) / Math.pow(PL + pPrev, 2);
            const d2VdP2Prev = -2 * VL * PL / Math.pow(PL + pPrev, 3);
            const curvaturePrev = Math.abs(d2VdP2Prev) / Math.pow(1 + Math.pow(dVdPPrev, 2), 1.5);
            
            const dVdPNext = (VL * PL) / Math.pow(PL + pNext, 2);
            const d2VdP2Next = -2 * VL * PL / Math.pow(PL + pNext, 3);
            const curvatureNext = Math.abs(d2VdP2Next) / Math.pow(1 + Math.pow(dVdPNext, 2), 1.5);
            
            // 应用中心差分计算曲率导数
            const dKdP = (curvatureNext - curvaturePrev) / (2 * step);
            
            // 检查是否已存在临界解吸压力计算点，如果存在则更新
            const existingPointIndex = calculationPoints.findIndex(point => 
                point.name === '临界解吸压力'
            );
            
            // 保存当前计算点信息
            const calculationPoint = {
                id: Date.now(),
                name: '临界解吸压力', // 指定名称为临界解吸压力
                pressure: pressure,
                volume: volume,
                curvature: curvature,
                curvatureDerivative: dKdP
            };
            
            if (existingPointIndex >= 0) {
                // 更新现有点
                calculationPoints[existingPointIndex] = calculationPoint;
            } else {
                // 添加到计算点数组
                calculationPoints.push(calculationPoint);
            }
            
            // 更新表格显示
            updateCalculationTable();
            
            // 使用更精确的方式重新绘制图表和标记点
            // 1. 首先清除所有现有标记点
            clearMarkPoint();
            
            // 2. 重新绘制主曲线（避免曲线消失问题）
            updateCharts(
                currentData.adsorptionData,
                currentData.firstDerivativeData,
                currentData.secondDerivativeData,
                currentData.curvatureData,
                currentData.curvatureDerivativeData,
                currentData.specialPoints
            );
            
            // 3. 逐个重新添加所有计算点
            calculationPoints.forEach((point, index) => {
                markPointOnCharts(point.pressure, point.volume, index);
            });
        }
        
        // 为含气量和临界解吸压力输入框添加事件监听器
        document.getElementById('gasContent').addEventListener('input', handleGasContentOrCriticalPressureChange);
        document.getElementById('criticalPressure').addEventListener('input', handleGasContentOrCriticalPressureChange);
        
        // 初始化复制表格数据按钮
        document.getElementById('copyTableBtn').addEventListener('click', copyTableToClipboard);
        
        // 复制表格数据到剪贴板
        function copyTableToClipboard() {
            // 获取表头数据
            const headers = Array.from(document.querySelectorAll('#resultTable th')).map(th => {
                // 移除单位信息，只保留列名
                return th.textContent.replace(/\s*\([^)]*\)/g, '').trim();
            });
            
            // 获取表格行数据
            const rows = Array.from(document.querySelectorAll('#resultTable tbody tr')).map(tr => {
                return Array.from(tr.querySelectorAll('td')).map((td, index) => {
                    // 对于名称列，获取输入框的值
                    if (index === 0) {
                        const input = td.querySelector('input');
                        return input ? input.value : td.textContent.trim();
                    }
                    // 其他列直接获取文本内容
                    return td.textContent.trim();
                });
            });
            
            // 如果没有数据，显示提示
            if (rows.length === 0 || rows[0].length === 0) {
                alert('表格中没有可复制的数据');
                return;
            }
            
            // 构建制表符分隔的文本（适合Excel粘贴）
            let tsvContent = headers.join('\t') + '\n';
            rows.forEach(row => {
                // 跳过空数据行
                if (row.length > 0 && !row.every(cell => cell === '')) {
                    tsvContent += row.join('\t') + '\n';
                }
            });
            
            // 复制到剪贴板
            navigator.clipboard.writeText(tsvContent).then(function() {
                alert('表格数据已成功复制到剪贴板，可以粘贴到Excel中');
            }).catch(function(err) {
                console.error('复制失败:', err);
                alert('复制失败，请重试');
            });
        }
        
        // 初始化时确保收缩状态正确
        document.addEventListener('DOMContentLoaded', function() {
            // 公式说明模块初始化
            const formulaContent = document.getElementById('formulaContent');
            const formulaIcon = document.getElementById('formulaToggleIcon');
            
            // 确保处于收缩状态
            formulaContent.classList.add('collapsed');
            formulaIcon.classList.remove('open');
            formulaContent.style.maxHeight = null;
            
            // 数据计算模块初始化
            const calcContent = document.getElementById('calculationContent');
            const calcIcon = document.getElementById('calculationToggleIcon');
            
            // 确保处于收缩状态
            calcContent.classList.add('collapsed');
            calcIcon.classList.remove('open');
            calcContent.style.maxHeight = null;
        });
    </script>
</body>
    <!-- 导出数据弹窗 -->
    <div id="exportModal" class="modal-overlay">
        <div class="modal-content">
            <div class="modal-header">
                <h3 class="modal-title">导出数据</h3>
                <button class="modal-close" onclick="closeExportModal()">&times;</button>
            </div>
            <div class="modal-body">
                <p>请选择导出格式：</p>
                <div class="export-option" onclick="exportExcel()">
                    <div class="export-icon">📊</div>
                    <div>
                        <strong>导出Excel表格</strong>
                        <p style="margin: 5px 0 0 0; color: #666; font-size: 14px;">导出CSV格式，可直接用Excel打开</p>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button onclick="closeExportModal()">取消</button>
            </div>
        </div>
    </div>
</html>